package io.gitee.xjt2016.modules.gen.controller;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.db.meta.JdbcType;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import io.gitee.xjt2016.modules.common.BaseController;
import io.gitee.xjt2016.modules.domain.Resource;
import io.gitee.xjt2016.modules.domain.vo.ResourceVo;
import io.gitee.xjt2016.modules.gen.domain.GenSchema;
import io.gitee.xjt2016.modules.gen.domain.GenTable;
import io.gitee.xjt2016.modules.gen.utils.GenUtil;
import io.gitee.xjt2016.modules.gen.utils.JdbcTypeJavaClassMappings;
import io.gitee.xjt2016.modules.service.ResourceService;
import lombok.extern.log4j.Log4j2;
import net.sf.jsqlparser.JSQLParserException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 参考网站实现代码生成，基于SQL.
 * https://tool.ityuan.com/gcode
 *
 * @author xiongjinteng@gmail.com
 */
@Log4j2
@Controller
@RequestMapping(value = "/gen")
public class GenController extends BaseController {

    public static final String module = "gen";
    public static final String pathPrefix = "/" + module;
    private static final String PARAM_KEY = "data";

    @Autowired
    ResourceService service;

    @ModelAttribute
    public void modelAttribute(Model model, HttpServletRequest request) {
        model.addAttribute("module", module);
        model.addAttribute("pathPrefix", pathPrefix);

        Map<String, ?> map = RequestContextUtils.getInputFlashMap(request);
        //model.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        if (map != null) {
            model.addAttribute("message", map.get("message") + "");
            model.addAttribute("code", map.get("code") + "");
        }

        List<Map<String, Object>> javaTypes = new JdbcTypeJavaClassMappings()
                .jdbcTypeCodeToJavaClassMap.values()
                .stream()
                .distinct()
                .map(s -> {
                    Map<String, Object> map1 = new HashMap<>();
                    map1.put("value", s.getSimpleName());

                    map1.put("text", s.getSimpleName());
                    return map1;
                }).collect(Collectors.toList());
        model.addAttribute("javaTypes", javaTypes);


        List<Map<String, Object>> jdbcTypes = Arrays.stream(JdbcType.values()).sorted().map(fieldDataType -> {
            Map<String, Object> map1 = new HashMap<>();
            map1.put("value", fieldDataType.toString().toLowerCase());
            map1.put("text", fieldDataType.toString().toLowerCase());
            return map1;
        }).collect(Collectors.toList());
        model.addAttribute("jdbcTypes", jdbcTypes);
    }

    @RequestMapping(value = {"/sql"})
    public String sql() throws Exception {
        return pathPrefix + "/sql";
    }

    @RequestMapping(value = {"/json", ""})
    public String json() throws Exception {
        return pathPrefix + "/json";
    }

    @ResponseBody
    @PostMapping(value = "/json2java")
    public Object json2java(String json) {
        return buildSuccessResponse(json);
    }

    @ResponseBody
    @GetMapping(value = {"/getListAll"})
    public Object getListAll() throws Exception {
        return buildSuccessResponse(service.list());
    }

    @ResponseBody
    @RequestMapping(value = {"/getList"})
    public Object getList(ResourceVo vo) throws Exception {
        IPage<Resource> page = initMyBatisPage(vo);
        page = service.page(page, Wrappers.lambdaQuery(Resource.class));
        return pageResponse(page);
    }

    @GetMapping(value = {"/form"})
    public String formGet(Long id, Model model) throws Exception {
        Resource form = null;
        if (id != null) {
            form = service.getById(id);
        }
        if (form == null) {
            form = new Resource();
        }
        model.addAttribute(PARAM_KEY, form);
        return pathPrefix + "/form";
    }

    @PostMapping(value = {"/form"})
    public ModelAndView formPost(Resource form, RedirectAttributes attributes) throws Exception {
        boolean result = service.saveOrUpdate(form);
        attributes.addFlashAttribute("message", result);
        attributes.addFlashAttribute("code", 100);
        return buildRedirectModelAndView(pathPrefix);
    }

    @ResponseBody
    @GetMapping(value = {"/delete"})
    public ModelAndView delete(String id, RedirectAttributes attributes) throws Exception {
        boolean result = service.removeByIds(split2LongList(id));
        attributes.addFlashAttribute("message", result);
        attributes.addFlashAttribute("code", 100);
        return buildRedirectModelAndView(pathPrefix);
    }

    @ResponseBody
    @PostMapping(value = "/uploadCreateSql")
    public Object uploadCreateSql(String sql) throws JSQLParserException {
        Preconditions.checkNotNull(sql);
        sql = sql.replaceAll("[\r\n]", "");
        log.info("create sql:{}", sql);
        return buildSuccessResponse(GenUtil.sql2GenTable(sql));
    }

    @ResponseBody
    @PostMapping(value = "/gen")
    public Object gen(String info, HttpServletRequest request, HttpServletResponse response) throws Exception {

        log.info("create info:{}", info);
        GenTable genTable = JSON.parseObject(info, GenTable.class);
        GenSchema genSchema = new GenSchema(genTable);

        genSchema.setModuleName("demo");
        genSchema.setBasePackageName(genTable.getBasePackage());
        genSchema.setEntityName(genTable.getEntityName());

        String id = UUID.randomUUID().toString();
        String path = FileUtil.getTmpDirPath() + File.separator + id;
        log.debug("gen path:{}", path);
        genSchema.setGenPath(path);

        GenUtil.genByGenTable(genSchema);

        //设置文件MIME类型
//        response.setContentType(getServletContext().getMimeType(filename));
        //设置Content-Disposition
        response.setHeader("Content-Disposition", "attachment;filename=" + id + ".zip");
        //读取目标文件，通过response将目标文件写到客户端
        //获取目标文件的绝对路径
        File file = ZipUtil.zip(FileUtil.file(path));
        //读取文件
        InputStream in = new FileInputStream(file);
        OutputStream out = response.getOutputStream();

        //写文件
        int b;
        while ((b = in.read()) != -1) {
            out.write(b);
        }
        in.close();
        return buildSuccessResponse("");
    }

    public static void main(String[] args) {
        String sql = "CREATE TABLE `function1` (\n" +
                "  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '自增',\n" +
                "  `project_id` int NOT NULL,\n" +
                "  `name` varchar(64) NOT NULL DEFAULT '',\n" +
                "  `description` varchar(256) DEFAULT NULL,\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci";
        System.out.println(JSON.toJSONString(GenUtil.sql2GenTable(sql), true));
    }
}
